package com.zsule.frameworks.mongodb.service;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.zsule.entity.MongoEntity;
import com.zsule.entity.PageEntity;
import com.zsule.frameworks.mongodb.dao.MongoDao;

public abstract class MongoAbstractService<T extends MongoEntity> {
	
	@Autowired
	private MongoDao<T> dao;
	
    private Class<T> entityClass;

    /**
     * 这个通常也是hibernate的取得子类class的方法
     * 
     */
    @SuppressWarnings("unchecked")
    public MongoAbstractService() {
        Type genType = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        entityClass = (Class<T>) params[0];
    }

    public MongoDao<T> getDao(){
    	return dao;
    }

    public T findAndRemoveFirst(Query query) {
        return getDao().findAndRemoveFirst(query, entityClass);
    }

    public List<T> findAndRemoveAll(Criteria criteria) {
        return findAndRemoveAll(new Query(criteria));
    }

    public List<T> findAndRemoveAll(Query query) {
        return getDao().findAndRemoveAll(query, entityClass);
    }

    public List<T> findAll(Class<T> entityClass) {
        return getDao().findAll(entityClass);
    }

    public long total(Class<T> entityClass) {
        return getDao().size(new Query(), entityClass);
    }

    public long size(Query query) {
        return getDao().size(query, entityClass);
    }

    public long size(Criteria criteria) {
        return size(new Query(criteria));
    }

    public List<T> findList(Criteria criteria) {
        return findList(criteria);
    }

    public List<T> findList(Query query) {
        return getDao().findList(query, entityClass);
    }

    public List<T> limitFind(int pageSize, int forward) {
        Query query = new Query();
        return limitFind(pageSize, forward, query);
    }

    public List<T> limitFind(Query query, PageEntity page) {
        long size = page.getTotalResultSize();
        if (size == 0l) {
            size = size(query);
            if (size == 0) {
                return new ArrayList<T>();
            }
            page.setTotalResultSize((int) size);
        }
        query.skip(page.getStartRow()).limit(page.getPageSize());
        return getDao().findList(query, entityClass);
    }

    public List<T> limitFind(int pageSize, int forward, Query query) {
        long size = size(query);
        int skip = (long) ((forward - 1) * pageSize) > size ? (int) size : (forward - 1) * pageSize;
        query.skip(skip).limit(pageSize);
        return getDao().findList(query, entityClass);
    }

    public T findOne(Query query) {
        return getDao().findOne(query, entityClass);
    }
    
    public T findOne(Criteria criteria) {
        return getDao().findOne(new Query(criteria), entityClass);
    }

    public T findById(String id) {
        return getDao().findById(id, entityClass);
    }

    public void remove(T entity) {
        getDao().remove(entity);
    }

    public void removeById(String id) {
        getDao().remove(findById(id));
    }

    public void save(T entity) {
        getDao().save(entity);
    }

    public void insert(T entity) {
        getDao().insert(entity);
    }

    public void insertBatch(List<T> entitys) {
        getDao().insertBatch(entitys, entityClass);
    }

    public void updateFirst(Query query, Update update) {
        getDao().updateFirst(query, update, entityClass);
    }

    public void updateAll(Query query, Update update) {
        getDao().updateAll(query, update, entityClass);
    }
    
    public void updateFirst(Criteria criteria, Update update) {
       updateFirst(new Query(criteria), update);
    }

    public void updateAll(Criteria criteria, Update update) {
        updateAll(new Query(criteria), update);
    }

    public T findAndModify(Query query, Update update) {
        return getDao().findAndModify(query, update, entityClass);
    }

    public void updateFirst(String whereKey, Object whereValue, String updateKey, Object updateValue) {
        updateFirst(new Query(Criteria.where(whereKey).is(whereValue)), Update.update(updateKey, updateValue));
    }

    public void updateAll(String whereKey, Object whereValue, String updateKey, Object updateValue) {
        updateAll(new Query(Criteria.where(whereKey).is(whereValue)), Update.update(updateKey, updateValue));
    }
}
